using Commons.Utils;
using System;
using System.Collections.Generic;
using System.Reflection;

namespace Commons.Injector
{
	public class DictionaryDefinition : ObjectDefinition
	{
		public List<DictionaryEntryDefinition> entries;
		public string objectRef;
		public string propertyRef;
		public MethodInfo addMethod;

		public DictionaryDefinition()
		{
			entries = new List<DictionaryEntryDefinition>();
			singleton = false;
		}

		public static object CreateGeneric(Type generic, Type innerType, params object[] args)
		{
			Type specificType = generic.MakeGenericType(new Type[] { typeof(string), innerType });
			return Activator.CreateInstance(specificType, args);
		}

		private MethodInfo GetAddMethod(object target, Type itemType)
		{
			return target.GetType().GetMethod("Add", new Type[] { typeof(string), itemType });
		}

		private void AddItem(object list, string key, object item)
		{
			if (addMethod != null)
			{
				addMethod.Invoke(list, new object[] { key, item });
			}
		}

		public void SetDictionaryValues(object dictionary, Dictionary<string,object> globalReferences, Dictionary<string,object> localReferences, Type innerType)
		{
			foreach (DictionaryEntryDefinition entryDef in entries)
			{
				object value;
				if (entryDef.refId == null)
				{
					if (innerType == typeof(Type))
					{
						value = Type.GetType(entryDef.value.ToString());
					}
					else
					{
						value = Convert.ChangeType(entryDef.value, innerType);
					}
				}
				else
				{
					value = localReferences.ContainsKey(entryDef.refId) ? localReferences[entryDef.refId] : globalReferences[entryDef.refId];
				}
				AddItem(dictionary, entryDef.key, value);
			}
		}

		public override object Instantiate(Dictionary<string, object> globalReferences, Dictionary<string,object> localReferences)
		{
			Type itemType = ReflectionHelper.GetCustomType(className);
			object dictionary = CreateGeneric(typeof(Dictionary<,>), itemType, null);
			addMethod = GetAddMethod(dictionary, itemType);
			SetDictionaryValues(dictionary, globalReferences, localReferences, itemType);

			return dictionary;
		}
	}
}
